#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#define NUM_THREADS 10

using namespace std;

//ios_base::sync_with_stdio(0);

typedef struct{
	long double a0, a1, b, t, pi;
	unsigned int p;
}dados;

void *setaA0(void*);
void *setaB(void*);
void *setaT(void*);
void *setaP(void*);
void *setaN(void*);
void *calculaA0(void*);
void *calculaA1(void*);
void *calculaB(void*);
void *calculaP(void*);
void *calculaT(void*);
void *calculaPI(void*);


int main(int argc,char**argv){
	if(argc < 2){
		cout << "usage ./prog <interactions>" << endl;
		return -1;
	}	

	int N;
	dados var;
	pthread_t threads[NUM_THREADS];
	
	
	pthread_create(&threads[0], NULL, setaN, (void*)&N);
	pthread_create(&threads[1], NULL, setaA0, (void*)&var.a0);
	pthread_create(&threads[2], NULL, setaB, (void*)&var.b);
	pthread_create(&threads[3], NULL, setaT, (void*)&var.t);
	pthread_create(&threads[4], NULL, setaP, (void*)&var.p);
	
	for(int i = 0; i < N; i++){
		pthread_create(&threads[5], NULL, calculaA1, (void*)&var);
		pthread_join(threads[5],NULL);
		pthread_create(&threads[6], NULL, calculaB, (void*)&var);
		//pthread_join(threads[6],NULL);
		pthread_create(&threads[7], NULL, calculaT, (void*)&var);
		pthread_join(threads[7],NULL);
		pthread_create(&threads[8], NULL, calculaP, (void*)&var);
		//pthread_join(threads[8],NULL);
		pthread_create(&threads[9], NULL, calculaPI, (void*)&var);
		//pthread_join(threads[9],NULL);
		pthread_create(&threads[10], NULL, calculaA0, (void*)&var);
		pthread_join(threads[10],NULL);
	}
	cout.precision(7);
	cout << "pi:" << var.pi << endl;
	return 0;
}

void *setaA0(void* valor){
	long double *aux = (long double*) valor;
	
	// a0 = 1;
	*aux = 1;
	pthread_exit(NULL);
}

void *setaB(void* valor){
	long double *aux = (long double*) valor;
	
	// b = 1 / sqrt(2);
	*aux = 1/sqrt(2);
	pthread_exit(NULL);
}

void *setaP(void* valor){
	unsigned int *aux = (unsigned int*) valor;
	
	// p = 1;
	*aux = 1;
	pthread_exit(NULL);
}

void *setaT(void* valor){
	long double *aux = (long double*) valor;
	
	// t = 0.25;
	*aux = 0.25;
	pthread_exit(NULL);
}

void *setaN(void* valor){
	int *aux = (int*) valor;
	
	// N = 1000000;
	*aux = 1000000;
	pthread_exit(NULL);
}

void *calculaA0(void* var){
	dados *f = (dados*) var;
	long double aux = f->a0;
	long double aux2 = f->a1;
	
	// a0 = a1;
	aux = aux2;
	f->a0 = aux;
	pthread_exit(NULL);
}

void *calculaA1(void* var){
	dados *f = (dados*) var;
	long double aux = f->a1;
	long double aux2 = f->a0;
	long double aux3 = f->b;
	
	// a1 = (a0 + b) / 2;
	aux = (aux2 + aux3) / 2;
	f->a1 = aux;
	
	pthread_exit(NULL);
}

void *calculaB(void* var){
	dados *f = (dados*) var;
	long double aux = f->b;
	long double aux2 = f->a0;
	
	// b = sqrt(a0 * b);
	aux = sqrt(aux2 * aux);
	f->b = aux;
	pthread_exit(NULL);
}

void *calculaT(void* var){
	dados *f = (dados*) var;
	long double aux = f->t;
	long double aux2 = f->p;
	long double aux3 = f->a0;
	long double aux4 = f->a1;
	
	// t = t - p * pow((a0 - a1),2);
	aux = aux - aux2 * pow((aux3 - aux4),2);
	f->t = aux;
	pthread_exit(NULL);
}

void *calculaP(void* var){
	dados *f= (dados*) var;
	unsigned int aux = f->p;
	
	// p = 2 * p;
	aux = aux * 2;
	f->p = aux;
	pthread_exit(NULL);
}

void *calculaPI(void* var){
	dados *f = (dados*) var;
	long double aux = f->pi;
	long double aux2 = f->a1;
	long double aux3 = f->b;
	long double aux4 = f->t;
	
	// pi = pow((a1 + b),2) / (4 * t);
	aux = pow((aux2 + aux3),2) / (4 * aux4);
	f->pi = aux;
	pthread_exit(NULL);
}



